﻿#include "ChatServer.h"
#include "XyNet/XyNet.h"

XYNET_IMPLEMENT_BASE_SINGLETON(XyNetTest::ChatServerManager);

namespace XyNetTest
{
	string ChatServerManager::initServer()
	{
		auto config = make_shared<XyNet::RpcServer::Config>();
		config->setPort(12345);
		config->setMessageTimeout(9999);
		//config->setMaxMessagePacketSize(999999999);
		//config->setMaxMessageCountPerSecond(5000);
		//config->setMaxDownloadSpeed(2000);
		//config->setMaxUploadSpeed(2000);
		//config->setEncryptionLevel(3);

		config->setCheckHeartBeatInterval(9999);
		//config->setMaxConnection(2);
		//config->setCheckHeartBeatInterval(2);

		_server = make_shared<XyNet::RpcServer>(config);
		_server->getServiceManager()->addService(
			std::make_shared<ServerUserServiceImpl>(_server.get()));

		return "localhost:" + lexical_cast<string>(config->getPort());
	}

	//////////////////////////////////////////////////////////////////////////

	ServerUserServiceImpl::ServerUserServiceImpl(XyNet::RpcServer* server) : _server(server) {}

	void ServerUserServiceImpl::onLogin(LoginMethod::Argument* argument)
	{
		// 检查是否已登录
		auto controller = argument->getController();
		if (controller->getUserId() > 0)
		{
			controller->setFailed(controller->AlreadyLogin);
			return;
		}

		// 给先前登陆用用户发异地登陆消息
		auto userId = argument->getRequest()->user_id();
		if (_server->isUserLogined(userId))
		{
			auto broadcastChannel = controller->createBroadcastChannel();
			broadcastChannel->setBroadcastSpecifiedUser(userId);
			ClientUserService::ElsewhereLoginMethod elsewhereLoginMethod(broadcastChannel);
			elsewhereLoginMethod.call();
		}

		// 设置当前用户id，广播完后再设置userId，以免发给新登录用户
		_server->setSocketChannelUserId(controller->getSocketChannelId(), userId);
		controller->getSocketChannelServiceManager()->addService(
			std::make_shared<ServerChatServiceImpl>(_server));	// 连接通道添加聊天服务

		auto broadcastChannel = controller->createBroadcastChannel();
		broadcastChannel->setBroadcastAllUsers();
		ClientUserService::OtherLoginMethod otherLoginMethod(broadcastChannel);
		otherLoginMethod.getRequest()->set_other_user_id(userId);
		otherLoginMethod.call();
	}

	void ServerUserServiceImpl::onLogout(LogoutMethod::Argument* argument)
	{
		auto controller = argument->getController();
		if (controller->getUserId() == 0)
		{
			controller->setFailed(controller->AlreadyLogout);
			return;
		}
		auto broadcastChannel = controller->createBroadcastChannel();
		broadcastChannel->setBroadcastAllUsers();
		ClientUserService::OtherLogoutMethod method(broadcastChannel);
		method.getRequest()->set_other_user_id(controller->getUserId());
		method.call();

		_server->setSocketChannelUserId(controller->getSocketChannelId(), 0);
		//controller->getConnectionChannelServiceManager()->clear();	// 清空连接通道服务
	}

	//////////////////////////////////////////////////////////////////////////

	ServerChatServiceImpl::ServerChatServiceImpl(XyNet::RpcServer* server) : _server(server) {}

	void ServerChatServiceImpl::onPublicSay(PublicSayMethod::Argument* argument)
	{
		auto controller = argument->getController();
		//if (controller->getUserId() == 0)
		//{
		//	controller->setFailed("未登录不能说话。");
		//	return;
		//}

		auto broadcastChannel = controller->createBroadcastChannel();
		broadcastChannel->setBroadcastLoginUsers();
		//broadcastChannel->setBroadcastAllUsers();
		ClientChatService::OtherPublicSayMethod method(broadcastChannel);
		method.getRequest()->set_other_user_id(controller->getUserId());
		method.getRequest()->set_other_message(argument->getRequest()->message());
		method.call();
	}

	void ServerChatServiceImpl::onPrivateSay(PrivateSayMethod::Argument* argument)
	{
		auto controller = argument->getController();
		auto sendToUserId = argument->getRequest()->other_user_id();
		//if (controller->getUserId() == 0)
		//{
		//	controller->setFailed("未登录不能说话。");
		//	return;
		//}

		if (_server->isUserLogined(sendToUserId))
		{
			auto broadcastChannel = controller->createBroadcastChannel();
			broadcastChannel->setBroadcastSpecifiedUser(sendToUserId);
			ClientChatService::OtherPrivateSayMethod method(broadcastChannel);
			method.getRequest()->set_other_user_id(controller->getUserId());
			method.getRequest()->set_other_message(argument->getRequest()->message());
			method.call();
		}
		else
		{
			boost::format format("目标用户%d未登陆");
			format % sendToUserId;
			controller->setFailed(controller->TargetUserNotLogin, format.str());
		}
	}
}